/*
 * oled_driver.c
 *
 *  Created on: 2024年3月8日
 *      Author: LeiWang
 */


#include "oled_driver.h"
#include "oled_font.h"

uint8_t oled_gram[128][8];		// oled显存
uint8_t temp_data[2] = {0};		// iic要发送给从机的数据

// 使用iic向oled发送数据
void oled_iic_write(uint8_t* data, uint16_t size){

	if (HAL_I2C_Master_Transmit(&OLED_IIC_HANDLE, OLED_IIC_ADDRESS, data, size, HAL_MAX_DELAY) != HAL_OK) {
	        // 处理错误
	        // Error_Handler();
	}
}

// 向oled写命令
void oled_write_cmd(uint8_t oled_cmd){
	temp_data[0] = 0x00;
	temp_data[1] = oled_cmd;
	oled_iic_write(temp_data,sizeof(temp_data));
}

// 向oled写数据
void oled_write_data(uint8_t oled_data){
	temp_data[0] = 0x40;
	temp_data[1] = oled_data;
	oled_iic_write(temp_data,sizeof(temp_data));
}


// 向oled发送数据或命令
void oled_write_byte(uint8_t data,OLED_WR_MODE mode){
	if(mode)
		oled_write_data(data);
	else
		oled_write_cmd(data);
}

//反显函数
void oled_color_turn(uint8_t i){
	if(i==0)
		oled_write_byte(0xA6,OLED_CMD);//正常显示
	if(i==1)
		oled_write_byte(0xA7,OLED_CMD);//反色显示
}

//屏幕旋转180度
void oled_display_turn(uint8_t i){
	if(i==0)
		{
			oled_write_byte(0xC8,OLED_CMD);//正常显示
			oled_write_byte(0xA1,OLED_CMD);
		}
	if(i==1)
		{
			oled_write_byte(0xC0,OLED_CMD);//反转显示
			oled_write_byte(0xA0,OLED_CMD);
		}
}



// 开启oled显示
void oled_display_on(void){

	oled_write_byte(0x8d,OLED_CMD);		// 使能电荷泵
	oled_write_byte(0x14,OLED_CMD);		// 开启电荷泵
	oled_write_byte(0xaf,OLED_CMD);		// 点亮屏幕
}

// 关闭oled显示
void oled_display_off(void){

	oled_write_byte(0x8d,OLED_CMD);		// 使能电荷泵
	oled_write_byte(0x10,OLED_CMD);		// 关闭电荷泵
	oled_write_byte(0xae,OLED_CMD);		// 关闭屏幕
}

// 更新显存到oled
void oled_refresh(void){

	uint8_t i,n;
	for(i=0;i<8;i++){
		oled_write_byte(0xb0+i,	OLED_CMD);		// 设置行起始地址
		oled_write_byte(0x02,	OLED_CMD);		// 设置低列起始地址  //这条命令作了修改。将0x00修改为0x02，使其可以适配1.3寸OLED屏幕
		oled_write_byte(0x10,	OLED_CMD);		// 设置高列起始地址
		for(n=0;n<128;n++){
			oled_write_byte(oled_gram[n][i],OLED_DATA);
		}
	}
}

// 清屏函数
void oled_clear(void){
	uint8_t i,n;
	for(i=0;i<8;i++){
		for(n=0;n<128;n++){
			oled_gram[n][i] = 0;
		}
	}
	oled_refresh();
}

// 在oled屏幕画点（x:0~127;y:0~63）
void oled_draw_point(uint8_t x,uint8_t y){
	uint8_t i,m,n;
	i=y/8;
	m=y%8;
	n=1<<m;
	oled_gram[x][i]|=n;
}

//在oled屏幕清除一个点（x:0~127;y:0~63）
void oled_clear_point(uint8_t x,uint8_t y){
	uint8_t i,m,n;
	i=y/8;
	m=y%8;
	n=1<<m;
	oled_gram[x][i]=~oled_gram[x][i];
	oled_gram[x][i]|=n;
	oled_gram[x][i]=~oled_gram[x][i];
}

//在指定位置显示一个字符,包括部分字符（x:0~127;y:0~63;size:选择字体 12/16/24;取模方式 逐列式）
void oled_show_char(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1){
	uint8_t i,m,temp,size2,chr1;
	uint8_t y0=y;
	size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
	chr1=chr-' ';  //计算偏移后的值
	for(i=0;i<size2;i++)
	{
		//temp=asc2_1206[chr1][i];
		if(size1==12)
        {temp=asc2_1206[chr1][i];} //调用1206字体
		else if(size1==16)
        {temp=asc2_1608[chr1][i];} //调用1608字体
		else return;

        for(m=0;m<8;m++)           //写入数据
        {
            if(temp&0x80)oled_draw_point(x,y);
            else oled_clear_point(x,y);
            temp<<=1;
            y++;
            if((y-y0)==size1)
            {
                y=y0;
                x++;
                break;
            }
		}
  }
}

//显示字符串
//x,y:起点坐标
//size1:字体大小
//*chr:字符串起始地址
void oled_show_string(uint8_t x,uint8_t y,char *chr,uint8_t size1){
	while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
	{
		oled_show_char(x,y,*chr,size1);
		x+=size1/2;
		if(x>128-size1)  //换行
		{
			x=0;
			y+=2;
    }
		chr++;
  }
}

//m^n
uint32_t oled_pow(uint8_t m,uint8_t n){
	uint32_t result=1;
	while(n--)
	{
	  result*=m;
	}
	return result;
}

// //显示2个数字
// //x,y :起点坐标
// //len :数字的位数
// //size:字体大小
void oled_show_num(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size1){
	uint8_t t,temp;
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
			if(temp==0)
			{
				oled_show_char(x+(size1/2)*t,y,'0',size1);
      }
			else
			{
				oled_show_char(x+(size1/2)*t,y,temp+'0',size1);
			}
  }

}

//配置写入数据的起始位置
void OLED_WR_BP(uint8_t x,uint8_t y){
	oled_write_byte(0xb0+y,OLED_CMD);//设置行起始地址
	oled_write_byte(((x&0xf0)>>4)|0x10,OLED_CMD);
	oled_write_byte((x&0x0f),OLED_CMD);
}

void oled_init(void){
	oled_write_byte(0xAE,OLED_CMD);//--turn off oled panel
	oled_write_byte(0x00,OLED_CMD);//---set low column address
	oled_write_byte(0x10,OLED_CMD);//---set high column address
	oled_write_byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
	oled_write_byte(0x81,OLED_CMD);//--set contrast control register
	oled_write_byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness
	oled_write_byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
	oled_write_byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
	oled_write_byte(0xA6,OLED_CMD);//--set normal display
	oled_write_byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	oled_write_byte(0x3f,OLED_CMD);//--1/64 duty
	oled_write_byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	oled_write_byte(0x00,OLED_CMD);//-not offset
	oled_write_byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
	oled_write_byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
	oled_write_byte(0xD9,OLED_CMD);//--set pre-charge period
	oled_write_byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	oled_write_byte(0xDA,OLED_CMD);//--set com pins hardware configuration
	oled_write_byte(0x12,OLED_CMD);
	oled_write_byte(0xDB,OLED_CMD);//--set vcomh
	oled_write_byte(0x40,OLED_CMD);//Set VCOM Deselect Level
	oled_write_byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
	oled_write_byte(0x02,OLED_CMD);//
	oled_write_byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
	oled_write_byte(0x14,OLED_CMD);//--set(0x10) disable
	oled_write_byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
	oled_write_byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
	oled_write_byte(0xAF,OLED_CMD);
	oled_clear();

	//OLED_Display_Status(Display_Clear);
	oled_pow(0,0);

}
